use crate::error::BizError;
use serde::{de::DeserializeOwned, Deserialize, Serialize};
use serde_json::Value;
use tracing::{error, info};
use validator::Validate;

use super::{AppState, SessionContext};

#[derive(Deserialize)]
pub struct RequestForm {
    pub service: String,
    pub biz_content: Option<String>,
}

#[derive(Debug)]
pub struct BizRequest {
    service: String,
    biz_content: Value,
    context: Option<SessionContext>,
    state: Option<AppState>,
}

impl BizRequest {
    pub fn new(
        service: &str,
        biz_content: Value,
        context: Option<SessionContext>,
        state: Option<AppState>,
    ) -> Self {
        Self {
            service: service.to_string(),
            biz_content,
            context,
            state,
        }
    }

    pub fn from_form(
        form: RequestForm,
        context: Option<SessionContext>,
        state: Option<AppState>,
    ) -> Result<Self, String> {
        let service = form.service;

        let biz_content = form.biz_content.unwrap_or("{}".to_string());

        let json_value = serde_json::from_str::<Value>(biz_content.as_str());

        let Ok(biz_content) = json_value else {
            return Err("biz_content内容必须为json形式的字符串".to_string());
        };

        Ok(Self::new(&service, biz_content, context, state))
    }

    pub fn get_service(&self) -> &str {
        &self.service
    }

    pub fn get_biz_content(&self) -> &Value {
        &self.biz_content
    }

    pub fn get_context(&self) -> Option<&SessionContext> {
        self.context.as_ref()
    }

    pub fn get_state(&self) -> Option<&AppState> {
        self.state.as_ref()
    }

    pub fn get_biz_model<T>(&self) -> Result<T, BizError>
    where
        T: DeserializeOwned + Validate,
    {
        let biz_content = self.get_biz_content();

        let json_value = serde_json::from_value::<T>(biz_content.clone());

        let Ok(biz_model) = json_value else {
            return Err(BizError::DeserializeError);
        };
        let Err(err) = biz_model.validate() else {
            return Ok(biz_model);
        };

        error!("[校验异常]{:?}", err);

        let errors = err.errors();
        let error_json = serde_json::to_value(errors).unwrap();

        Err(BizError::InvalidParams(Some(error_json)))
    }
}

/**
 * ====================
 *  分页请求
 * ====================
 */

#[derive(Debug, Deserialize, Serialize, Validate)]
pub struct PageRequest<T: Validate> {
    #[validate(range(min = 1, message = "页码必须大于0"))]
    pub page_num: u64,

    #[validate(range(min = 1, message = "页码必须大于0"))]
    pub page_size: u64,

    pub params: Option<T>,
}

impl<T> TryFrom<&Value> for PageRequest<T>
where
    T: DeserializeOwned + Validate,
{
    type Error = BizError;
    fn try_from(value: &Value) -> Result<Self, Self::Error> {
        let params = serde_json::from_value::<PageRequest<T>>(value.clone());

        if params.as_ref().is_err() {
            error!("json序列化失败{}", params.err().unwrap());
            return Err(BizError::DeserializeError);
        }

        let params = params.unwrap();

        let Err(err) = params.validate() else {
            return Ok(params);
        };

        error!("[校验异常]{:?}", err);

        let errors = err.errors();
        let error_json = serde_json::to_value(errors).unwrap();

        Err(BizError::InvalidParams(Some(error_json)))
    }
}

#[derive(Debug, Deserialize, Serialize)]
pub struct PageResponse<T> {
    pub page_num: u64,
    pub page_size: u64,
    pub total: u64,
    pub list: Vec<T>,
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn test_page_request() {
        #[derive(Debug, Deserialize, Serialize, Validate)]
        struct ReqBody {
            #[validate(length(min = 1, message = "名称不得为空"))]
            pub name: String,
        }

        let request: PageRequest<ReqBody> = PageRequest {
            page_num: 0,
            page_size: 20,
            params: None,
        };

        println!("{:?}", request.validate());

        let request: PageRequest<ReqBody> = PageRequest {
            page_num: 1,
            page_size: 20,
            params: Some(ReqBody {
                name: "".to_string(),
            }),
        };

        println!("{:?}", request.validate());

        let res = request.validate();
        let err = res.err().unwrap();
        println!("{:?}", err.errors());
        println!("{:?}", err.to_string());
    }
}
